home *** CD-ROM | disk | FTP | other *** search
Text File | 1997-03-21 | 25.6 KB | 922 lines | [TEXT/CWIE] |
- //
- // CAGASlider.cp
- //
- // Apple Grayscale Appearance Slider class for PowerPlant
- // Subclassed from LControl
- //
- // version 1.4.2 - March 21, 1997
- //
- // Copyright © 1996-1997 by James Jennings. All rights reserved.
- //
- /*
- Optimization notes: I basically did three things (in slider v1.3.1)
- 1. Calculated the smallest rectangle to redraw while tracking the mouse.
- (stored in mChangedRect)
- 2. Don't draw tick marks while tracking the mouse.
- (This assumes the tick marks won't change while tracking.)
- 3. Precalculated the value returned by GetTrackRect() and cached it.
- (stored in mTrackRect)
-
- The StOffscreenGWorld constructor calls EraseRect() unnecessarily
- since I later erase everything to a light gray.
- I can't fix this without rewriting StOffscreenGWorld and have declined to
- do this at present. This could be done later if necessary.
- */
-
- // A thought:
- // We can replace mIsTracking with IsTracking() { return GetValue() != mTrackingValue; }
-
- // Uncomment the next line to turn on profiling for drawing and tracking.
- //#include <profiler.h>
-
- #include "CAGASlider.h"
- #include <LStream.h>
- #include <UDrawingUtils.h>
- #include <UDrawingState.h>
- #include <PP_Messages.h>
- #include <UGWorld.h>
-
- // Note that the flag AGA_VERSION won't change the indicator/thumb.
- // You have to replace the PICT 1000 resource for that.
- //#define AGA_VERSION 1 // Apple's specs as of April 96
- #define AGA_VERSION 2 // Apple's specs as of Sept 96
-
- // constants that control the geometry of the slider
- static const Int16 kEndMargin = 10; // where the indicator stops.
- static const Int16 kFlatMargin = 4; // margin on the flat side on an indicator
- static const Int16 kPointMargin = 6; // margin on the pointy side--not including tickmarks
- static const Int16 kTrackWidth = 5; // width of the indicator's track
- static const Int16 kOffsideCutoff = 24; // abort by dragging this far from control
- static const Int16 kTrackToTick = 10; // center of track to start of tick mark
- static const Int16 kTickLen = 6; // length of tick mark
- static const Int16 kIndSize = 16; // size of indicator image
- static const Int16 kDepthCutoff = 4;// 4 or 8. The screen depth to start grayscale drawing.
-
- // If there are no tick marks, the slider is 16 pixels wide.
- // If there are tick marks, the slider is approximately...
- //const Int16 kSliderWidth = kFlatMargin+kTrackWidth+kTrackToTick+kTickLen; // = 25 pixels
-
- // Class variables for holding the indicator image data.
- LGWorld * CAGASlider::sColorData = 0;
- LGWorld * CAGASlider::sBlackAndWhiteData = 0;
- LGWorld * CAGASlider::sMaskData = 0;
-
- // Indicator image related constants.
- const Rect kPICTDataSize = { 0, 0, 6*kIndSize, 4*kIndSize };
- const ResIDT k8BitPICTid = 1000;
- const ResIDT k1BitPICTid = 1001;
- const ResIDT kMaskPICTid = 1002;
-
- CAGASlider* CAGASlider::CreateFromStream(LStream *inStream)
- {
- return new CAGASlider( inStream );
- }
-
- CAGASlider::CAGASlider(LStream *inStream)
- : LControl( inStream ), mState(ind_Enabled), mContinuousBroadcast(true),
- mIsTracking(false), mTrackingValue(0), mMinIsBottomOrRight(false)
- {
- GetColor( ga_Background, mBackground );
-
- Int32 directionCode;
- inStream->ReadBlock( &directionCode, sizeof(directionCode) );
-
- // Convert the entered code to the enumerated type
- switch ( directionCode ) {
- case 'hori': mDirection = ind_Horizontal; break;
- case 'vert': mDirection = ind_Vertical; break;
- case 'nort': mDirection = ind_North; break;
- case 'sout': mDirection = ind_South; break;
- case 'east': mDirection = ind_East; break;
- case 'west': mDirection = ind_West; break;
- default: // anything else (like 'prop'), base on the proportions of the pane
- SDimension16 theSize;
- GetFrameSize( theSize );
- if ( theSize.width > theSize.height ) mDirection = ind_Horizontal;
- else mDirection = ind_Vertical;
- break;
- }
-
- // If mNumberOfTicks = 0, don't display any tick marks
- // If mNumberOfTicks = 1, display one tick mark per value
- // If mNumberOfTicks > 1, then mNumberOfTicks is the number of tickmarks (intervals + 1)
- inStream->ReadBlock( &mNumberOfTicks, sizeof(mNumberOfTicks) );
-
- // mContinuousBroadcast == true -> broadcast change everytime the indicator moves
- // mContinuousBroadcast == false -> wait for mouseUp
- inStream->ReadBlock( &mContinuousBroadcast, sizeof(mContinuousBroadcast) );
-
- // mMinIsBottomOrRight == false -> mValue increases as you slide down or right
- // Behaves like a standard scrollbar.
- // mMinIsBottomOrRight == true -> mValue increases as you slide up or left
- // Is more intuitive for vertical sliders.
- inStream->ReadBlock( &mMinIsBottomOrRight, sizeof(mMinIsBottomOrRight) );
-
- // do we need this line?
- // mState = ( (mEnabled != triState_Off) ? ind_Enabled : ind_Disabled);
-
- CalcTrackRect();
- CalcLocalFrameRect(mChangedRect); // reasonable default value
- }
-
- CAGASlider::CAGASlider(const CAGASlider &inSlider) // copy constructor
- : LControl( inSlider ), mState( ind_Enabled ), mIsTracking( false ), mTrackingValue( 0 ),
- mDirection( inSlider.mDirection ),
- mNumberOfTicks( inSlider.mNumberOfTicks ),
- mContinuousBroadcast( inSlider.mContinuousBroadcast ),
- mMinIsBottomOrRight( inSlider.mMinIsBottomOrRight )
- {
- CalcTrackRect();
- CalcLocalFrameRect(mChangedRect); // reasonable default value
- }
-
- CAGASlider::~CAGASlider()
- {
- }
-
- void CAGASlider::Purge()
- { // Release the memory containing the indicator images. (Not directly used by the class.)
- // Call it when memory is low, or when a window full of sliders is closed.
- // It doesn't hurt to call this too often, since the sliders will reallocate
- // the images if necessary.
- //
- // If you don't want to be aggressive about reclaiming memory,
- // you don't have to call this at all. The images only take a few K.
-
- if ( sColorData != nil ) {
- delete sColorData;
- sColorData = nil;
- }
-
- if ( sBlackAndWhiteData != nil ) {
- delete sBlackAndWhiteData;
- sBlackAndWhiteData = nil;
- }
-
- if ( sMaskData != nil ) {
- delete sMaskData;
- sMaskData = nil;
- }
- }
-
- void CAGASlider::DrawSelf(void)
- {
- #ifdef __PROFILER__
- Boolean profilerIsOn = ProfilerGetStatus();
- ProfilerSetStatus(true); // turn on the profiler
- #endif
- Rect theFrame, r;
- if (mIsTracking) {
- // optimize by only drawing what changes (new in slider v 1.3.1
- theFrame = mChangedRect;
- } else {
- CalcLocalFrameRect( theFrame );
- }
-
- StDeviceLoop devices(theFrame);
- Int16 depth;
-
- while (devices.NextDepth(depth)) {
-
- Boolean useGrays = (depth >= kDepthCutoff);
-
- // find the overlap between the frame and the current device
- r = (*devices.GetCurrentDevice())->gdRect;
- ::GlobalToLocal(&topLeft(r));
- ::GlobalToLocal(&botRight(r));
- if ( !::SectRect( &theFrame, &r, &r ) ) continue;
-
- // Detect the background color so we may fill the offscreen world correctly.
- if ( useGrays )
- DetectBackgroundColor();
- // RGBColor theBackground;
- // if (useGrays)
- // GetBackground( theBackground );
-
- // Use an offscreen world to avoid flickering
- StOffscreenGWorld offscreen( r, depth );
-
- DrawBackground( r, useGrays );
- /* if (useGrays) {
- // fill in the offscreen world with the background color
- ::RGBBackColor( &theBackground );
- ::EraseRect( &r );
- }
- */
- DrawSelfBasic(useGrays);
-
- }
- #ifdef __PROFILER__
- ProfilerSetStatus(profilerIsOn); // turn off the profiler
- #endif
- }
-
- void CAGASlider::DrawSelfBasic( Boolean useGrays )
- {
- // Rect theFrame;
- // CalcLocalFrameRect( theFrame );
- StColorPenState::Normalize();
-
- EIndicatorState theState = ( IsEnabled() ? mState : ind_Disabled );
-
- DrawTrack( theState, useGrays );
-
- if ( !mIsTracking ) // don't need ticks while tracking indicator
- DrawTickMarks( mNumberOfTicks, theState, useGrays );
-
- if ( mIsTracking ) // Draw ghost indicator
- DrawIndicator( mTrackingValue, ind_Ghost, useGrays );
-
- // Draw indicator *over* the ghost if they overlap.
- DrawIndicator( GetValue(), theState, useGrays );
- }
-
- void CAGASlider::DrawTrack( EIndicatorState inState, Boolean inUseGrays )
- {
- StColorPenState::Normalize();
-
- Rect r;
- GetTrackRect( r );
-
- const Int16 kRoundness = 4;
-
- // Colors depend on inState
- EGAColor black, gray;
- if ( inState == ind_Disabled ) {
- gray = ga_4;
- black = ga_8;
- } else {
- gray = ga_5;
- black = ga_Black;
- }
-
- if ( inUseGrays ) {
- #if (AGA_VERSION==2)
- if (inState != ind_Disabled) {
- #endif
- // Draw white and gray hilites
- r.bottom++;
- r.right++;
- SetForeColor( ga_White );
- ::PaintRoundRect( &r, kRoundness, kRoundness );
-
- ::OffsetRect( &r, -1, -1 );
- SetForeColor( gray );
- ::PaintRoundRect( &r, kRoundness, kRoundness );
-
- r.top++;
- r.left++;
- #if (AGA_VERSION==2)
- } else {
-
- // A disabled track still needs a fill color
- SetForeColor( gray );
- ::PaintRoundRect( &r, kRoundness, kRoundness );
-
- }
- #endif
- SetForeColor( black );
- } else {
- if (inState == ind_Disabled)
- ::PenPat(&UQDGlobals::GetQDGlobals()->gray);
- }
- ::FrameRoundRect( &r, kRoundness, kRoundness );
- }
-
- void CAGASlider::DrawIndicator( Int32 inValue, EIndicatorState inState, Boolean inUseGrays )
- {
- // where to draw it
- Rect r;
- ValueToIndicatorRect( inValue, r );
-
- //Commented out old version of the code: It didn't work in all cases.
- //ResIDT icon = ind_First_ics8_ID + inDirection * ind_StateOffset + inState;
- //DrawIcon1( r, icon, inUseGrays ); break;
-
- DrawIcon( r, mDirection, inState, inUseGrays );
- }
-
- /*
- DrawIcon1() was my prefered method of drawing the indicator.
- It did not work on all monitors on all machines.
- It also failed under QuickDrawGX.
- Is there a bug in the PPC version of the Toolbox code?
-
- void CAGASlider::DrawIcon1( Rect inWhere, ResIDT inWhich, Boolean inUseGrays )
- {
- OSErr anErr;
- // PlotIconID() needs a 16x16 rectangle.
- inWhere.bottom = inWhere.top + kIndSize;
- inWhere.right = inWhere.left + kIndSize;
-
- anErr = ::PlotIconID( &inWhere, atNone, ttNone, inWhich );
- ThrowIfOSErr_( anErr );
- }
- */
-
- void CAGASlider::DrawIcon( Rect inWhere, EIndicatorDirection inDirection,
- EIndicatorState inState, Boolean inUseGrays )
- { // draw the indicator out of a PICT
-
- // PlotIconID() needs a 16x16 rectangle.
- inWhere.bottom = inWhere.top + kIndSize;
- inWhere.right = inWhere.left + kIndSize;
-
- // we initialize the data we need (only does something on the first call)
- if ( inUseGrays ) InitColorData();
- else InitBlackAndWhiteData();
-
- GWorldPtr imageWorld = (inUseGrays ? sColorData : sBlackAndWhiteData )->GetMacGWorld();
- GWorldPtr maskWorld = sMaskData->GetMacGWorld();
- Assert_( imageWorld != nil && maskWorld != nil );
-
- PixMapHandle image = ::GetGWorldPixMap( imageWorld );
- PixMapHandle mask = ::GetGWorldPixMap( maskWorld );
- ThrowIfNil_( image );
- ThrowIfNil_( mask );
-
- Boolean notPurged;
- notPurged = ::LockPixels( image );
- notPurged = ::LockPixels( mask );
-
- Rect r = {0,0,kIndSize,kIndSize};
- Rect maskRect = r;
- ::OffsetRect( &r, inState * kIndSize, inDirection * kIndSize );
- ::OffsetRect( &maskRect, 0, inDirection * kIndSize );
-
- GrafPtr thePort;
- ::GetPort( & thePort );
-
- ::ForeColor( blackColor );
- ::BackColor( whiteColor );
- // ::CopyMask( srcBits, maskBits, dstBits, srcRect, maskRect, dstRect );
- ::CopyMask( (BitMapPtr)*image, (BitMapPtr)*mask, &(thePort->portBits),
- &r, &maskRect, &inWhere );
-
- ::UnlockPixels( image );
- ::UnlockPixels( mask );
- }
-
- void CAGASlider::InitColorData()
- {
- InitMaskData();
-
- if ( sColorData != nil ) return;
-
- sColorData = new LGWorld( kPICTDataSize, 8 );
- ThrowIfNil_( sColorData );
-
- InitPICTDataHelper( sColorData, k8BitPICTid, kPICTDataSize );
- }
-
- void CAGASlider::InitBlackAndWhiteData()
- {
- InitMaskData();
-
- if ( sBlackAndWhiteData != nil ) return;
-
- sBlackAndWhiteData = new LGWorld( kPICTDataSize, 1 );
- ThrowIfNil_( sBlackAndWhiteData );
-
- InitPICTDataHelper( sBlackAndWhiteData, k1BitPICTid, kPICTDataSize );
- }
-
- void CAGASlider::InitMaskData()
- {
- if ( sMaskData != nil ) return;
-
- Rect r = kPICTDataSize;
- r.right = r.left + kIndSize;
- sMaskData = new LGWorld( r, 1 );
- ThrowIfNil_( sMaskData );
-
- InitPICTDataHelper( sMaskData, kMaskPICTid, r );
- }
-
- void CAGASlider::InitPICTDataHelper( LGWorld *inWorld, const ResIDT inPICT, const Rect inRect )
- {
- PicHandle aPicH = ::GetPicture( inPICT );
- ThrowIfNil_( aPicH );
-
- inWorld->BeginDrawing();
- ::DrawPicture( aPicH, &inRect );
- inWorld->EndDrawing();
-
- ::ReleaseResource( (Handle)aPicH );
- }
-
- void CAGASlider::DetectBackgroundColor()
- {
- // The Problem:
- // Alas, the slider will not always be drawn on a ga_2 background.
- // The "Front Tab" pane has a ga_1 background.
- // To solve this problem, I will attempt to detect the background color
- // that is presumably drawn by the enclosing view.
-
- Rect trackRect;
- GetTrackRect( trackRect );
-
- // There should be a background pixel just beyond the top left corner of the trackRect
- // either when the slider is first drawn, or when tracking the mouse.
- ::GetCPixel( trackRect.left - 1, trackRect.top - 1, &mBackground);
- }
-
- void CAGASlider::DrawBackground( const Rect &inRect, Boolean inUseGrays )
- {
- // Fill in the offscreen world with the background color.
- // Override this method if you have a non-solid background. (eg: a pattern)
- if ( inUseGrays ) {
- ::RGBBackColor( &mBackground );
- ::EraseRect( &inRect );
- }
- }
-
- void CAGASlider::DrawTickMarks( UInt16 inNumber, EIndicatorState inState, Boolean inUseGrays )
- {
- if ( inNumber == 0 ) return;
- if ( inNumber == 1 ) inNumber = mMaxValue - mMinValue + 1;
- if ( inNumber <= 1 ) return;
- // Only "pointy" indicators have tickmarks.
- if ( mDirection == ind_Horizontal || mDirection == ind_Vertical ) return;
-
- Rect theTrack;
- GetTrackRect( theTrack );
-
- // Calculate the first tick mark rect, and the last tick mark position
- Rect firstTick;
- Point p = ValueToPosition( mMinValue ); // pos of 1st tick
- Point q = ValueToPosition( mMaxValue ); // pos of last tick
- switch ( mDirection ) { // SetRect( r, left, top, right, bottom ), SetPt( p, h, v )
- case ind_North:
- p.v -= kTrackToTick + kTickLen + 1;
- q.v -= kTrackToTick + kTickLen + 1;
- ::SetRect( &firstTick, p.h, p.v, p.h + 1, p.v + kTickLen );
- break;
- case ind_South:
- p.v += kTrackToTick;
- q.v += kTrackToTick;
- ::SetRect( &firstTick, p.h, p.v, p.h + 1, p.v + kTickLen );
- break;
- case ind_East:
- p.h += kTrackToTick;
- q.h += kTrackToTick;
- ::SetRect( &firstTick, p.h, p.v, p.h + kTickLen, p.v + 1 );
- break;
- case ind_West:
- p.h -= kTrackToTick + kTickLen + 1;
- q.h -= kTrackToTick + kTickLen + 1;
- ::SetRect( &firstTick, p.h, p.v, p.h + kTickLen, p.v + 1 );
- break;
- case ind_Horizontal:
- case ind_Vertical:
- default:
- SignalPStr_("\pBad Slider Class Member");
- }
-
- Int32 intervals = inNumber - 1;
- Assert_( intervals > 0 );
- for( Int32 i = 0; i <= intervals; i++ ) {
-
- Int16 deltah = (q.h - p.h) * i / intervals;
- Int16 deltav = (q.v - p.v) * i / intervals;
- Rect r = firstTick;
- ::OffsetRect( &r, deltah, deltav );
-
- if ( inUseGrays ) {
-
- // Colors depend on inState
- EGAColor black, gray;
- if ( inState == ind_Disabled ) {
- gray = ga_4;
- black = ga_8;
- } else {
- gray = ga_7;
- black = ga_Black;
- }
-
- PaintRect( r, black );
-
- #if AGA_VERSION==2
- if ( inState != ind_Disabled ) {
- ::InsetRect( &r, -1, -1 );
- UGrayscaleAppearance::FrameRect( r, ga_White, gray, ga_Background );
- }
- #else
- ::InsetRect( &r, -1, -1 );
- UGrayscaleAppearance::FrameRect( r, ga_White, gray, ga_Background );
- #endif
-
- } else {
-
- if (inState == ind_Disabled)
- ::PenPat(&UQDGlobals::GetQDGlobals()->gray);
- ::PaintRect( &r );
-
- }
- }
- }
-
- CAGASlider::EOrientation CAGASlider::GetOrientation(void)
- {
- EOrientation theResult;
- switch ( mDirection ) {
- case ind_Horizontal:
- case ind_North:
- case ind_South:
- theResult = orient_Horizontal;
- break;
- case ind_Vertical:
- case ind_East:
- case ind_West:
- theResult = orient_Vertical;
- break;
- default:
- SignalPStr_("\pBad Slider Class Member");
- }
- return theResult;
- }
-
- void CAGASlider::ValueToIndicatorRect( Int32 inValue, Rect &outRect )
- {
- Point center = ValueToPosition( inValue );
-
- switch ( mDirection ) {
- case ind_Horizontal:
- // SetRect() arguments are: Rect*, left, top, right, bottom
- ::SetRect( &outRect, center.h - 6, center.v - 8, center.h + 7, center.v + 8 );
- break;
- case ind_North:
- ::SetRect( &outRect, center.h - 7, center.v -10, center.h + 8, center.v + 6 );
- break;
- case ind_South:
- ::SetRect( &outRect, center.h - 7, center.v - 7, center.h + 8, center.v + 9 );
- break;
- case ind_Vertical:
- ::SetRect( &outRect, center.h - 8, center.v - 6, center.h + 8, center.v + 7 );
- break;
- case ind_East:
- ::SetRect( &outRect, center.h - 7, center.v - 7, center.h + 9, center.v + 8 );
- break;
- case ind_West:
- ::SetRect( &outRect, center.h -10, center.v - 7, center.h + 6, center.v + 8 );
- break;
- default:
- SignalPStr_("\pBad Slider Class Member");
- }
- }
-
- Point CAGASlider::ValueToPosition( Int32 inValue )
- { // find the position of the center of the indicator that corresponds to inValue
- Point p; // the result
-
- Assert_( mMinValue <= inValue && inValue <= mMaxValue );
-
- Int32 valueRange = mMaxValue - mMinValue;
- Int16 pixelRange;
-
- // Handle special case to avoid a divide by zero later.
- if ( valueRange <= 0 ) {
- inValue = mMinValue;
- valueRange = 1;
- }
-
- // Flip the direction of increasing value, if asked.
- Int32 startValue;
- if ( mMinIsBottomOrRight ) {
- startValue = mMaxValue;
- valueRange = - valueRange;
- } else {
- startValue = mMinValue;
- }
-
- Rect theTrack;
- GetTrackRect( theTrack );
-
- // Non-pointy indicators (which have no tick marks) aren't as
- // wide, so we adjust the placement.
- Int16 margin = kEndMargin;
- if ( mDirection == ind_Horizontal || mDirection == ind_Vertical ) margin--;
-
- switch( GetOrientation() ) {
- case orient_Horizontal:
- theTrack.right--; // aesthetic adjustments
- theTrack.bottom++;
- pixelRange = theTrack.right - theTrack.left - 2*margin;
- p.h = theTrack.left + margin +
- pixelRange * (inValue - startValue) / valueRange;
- p.v = ( theTrack.top + theTrack.bottom )/2;
- break;
- case orient_Vertical:
- theTrack.bottom--; // aesthetic adjustments
- theTrack.right++;
- pixelRange = theTrack.bottom - theTrack.top - 2*margin;
- p.v = theTrack.top + margin +
- pixelRange * (inValue - startValue) / valueRange;
- p.h = ( theTrack.right + theTrack.left )/2;
- break;
- default:
- SignalPStr_("\pBad Slider Orientation");
- break;
- }
-
- return p;
- }
-
- Int32 CAGASlider::PositionToValue( Point inPosition )
- {
- // Handle special case to avoid a divide by zero later.
- if ( mMaxValue <= mMinValue ) return mMinValue;
-
- Rect theTrack;
- GetTrackRect( theTrack );
-
- // If we move the mouse too far away from the slider,
- // return the slider's old value (thus aborting the slide).
- Point offside = {0,0}; // number of pixels off to the side of the slider
-
- if ( inPosition.v < theTrack.top ) offside.v = theTrack.top - inPosition.v;
- if ( inPosition.v > theTrack.bottom ) offside.v = inPosition.v - theTrack.bottom;
- if ( inPosition.h < theTrack.left ) offside.h = theTrack.left - inPosition.h;
- if ( inPosition.h > theTrack.right ) offside.h = inPosition.h - theTrack.right;
-
- if ( (offside.h > kOffsideCutoff) || (offside.v > kOffsideCutoff) )
- return GetValue(); // we're "offside" -- return the slider's current value
-
- // Calculate the value.
-
- Int32 offset, range, result;
-
- switch( GetOrientation() ) {
- case orient_Horizontal:
- offset = inPosition.h - theTrack.left - kEndMargin;
- range = theTrack.right - theTrack.left - 2*kEndMargin;
- Assert_( range > 0 );
- break;
- case orient_Vertical:
- offset = inPosition.v - theTrack.top - kEndMargin;
- range = theTrack.bottom - theTrack.top - 2*kEndMargin;
- Assert_( range > 0 );
- break;
- default:
- SignalPStr_("\pBad Slider Orientation");
- break;
- }
-
- // Flip the direction of increasing value, if asked.
- if ( mMinIsBottomOrRight )
- offset = range - offset;
-
- // Adjust the offset to center the indicator-value on a tick mark instead of between them.
- offset += range / ( mMaxValue - mMinValue ) / 2;
-
- // calculate result
- result = mMinValue + ( mMaxValue - mMinValue ) * offset / range;
-
- // range clipping
- if ( result < mMinValue ) result = mMinValue;
- if ( result > mMaxValue ) result = mMaxValue;
-
- return result;
- }
-
- void CAGASlider::ResizeFrameBy(Int16 inWidthDelta, Int16 inHeightDelta, Boolean inRefresh)
- {
- LControl::ResizeFrameBy( inWidthDelta, inHeightDelta, inRefresh);
- CalcTrackRect();
- }
-
- void CAGASlider::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
- {
- LControl::MoveBy( inHorizDelta, inVertDelta, inRefresh);
- CalcTrackRect();
- }
-
- void CAGASlider::GetTrackRect( Rect &outRect )
- {
- // Optimize by caching the track rectangle. (New in slider v1.3.1)
- outRect = mTrackRect;
- }
-
- void CAGASlider::CalcTrackRect()
- { // Calculate the rectange to draw the track into.
- //
- // This is the rect of the small black RoundRect. The white and gray highlights
- // are outside this rect. Try to base all drawing on this rect.
- //
- // The compass direction sliders are pushed to the side of the pane away from the point.
- // The plain sliders are centered.
-
- CalcLocalFrameRect( mTrackRect );
-
- SDimension16 theSize;
- GetFrameSize( theSize );
-
- // Center the track in the frame
- switch ( GetOrientation() ) {
-
- case orient_Horizontal:
-
- switch ( mDirection ) {
- case ind_Horizontal:
- mTrackRect.top += (theSize.height - kTrackWidth)/2;
- break;
- case ind_North:
- mTrackRect.top = mTrackRect.bottom - kFlatMargin - kTrackWidth;
- break;
- case ind_South:
- mTrackRect.top += kFlatMargin;
- break;
- }
- mTrackRect.bottom = mTrackRect.top + kTrackWidth;
- mTrackRect.left++;
- mTrackRect.right--;
- break;
-
- case orient_Vertical:
-
- switch ( mDirection ) {
- case ind_Vertical:
- mTrackRect.left += (theSize.width - kTrackWidth)/2;
- break;
- case ind_East:
- mTrackRect.left += kFlatMargin;
- break;
- case ind_West:
- mTrackRect.left = mTrackRect.right - kFlatMargin - kTrackWidth;
- break;
- }
- mTrackRect.right = mTrackRect.left + kTrackWidth;
- mTrackRect.top++;
- mTrackRect.bottom--;
- break;
- }
- }
-
- Int16 CAGASlider::FindHotSpot(Point inPoint) // Rewrite w/o icons !!!
- {
- // default is None.
- Int16 result = hot_None;
-
- // Is it in the track?
- Rect r;
- GetTrackRect( r );
- ::InsetRect( &r, -2, -2 );
-
- if ( ::PtInRect( inPoint, &r ) ) result = hot_Track;
-
- // Is it in the indicator? If so, override track.
- ValueToIndicatorRect( GetValue(), r );
-
- // code which relys on the PICT mask
- if ( ::PtInRect( inPoint, &r ) ) {
-
- Point p;
- p.h = inPoint.h - r.left;
- p.v = inPoint.v - r.top + mDirection * kIndSize;
-
- // test the value of the pixel in the mask PICT (is there a toolbox call for this?)
- InitMaskData();
- PixMapHandle pm = ::GetGWorldPixMap( sMaskData->GetMacGWorld() );
- Assert_( pm != nil );
-
- Ptr aPtr = ::GetPixBaseAddr( pm );
- Int16 rowBytes = (*pm)->rowBytes & 0x3FFF;
- aPtr += rowBytes * p.v + (p.h/8);
-
- if ( *aPtr & (1<<(7 - (p.h%8))) )
- result = hot_Indicator;
- }
-
- return result;
- }
-
- Boolean CAGASlider::PointInHotSpot(Point inPoint, Int16 inHotSpot)
- {
- if ( inHotSpot == 0 ) return false;
-
- return ( FindHotSpot( inPoint ) == inHotSpot );
- }
-
- void CAGASlider::HotSpotAction(Int16 inHotSpot, Boolean inCurrInside, Boolean inPrevInside)
- { // Not used? Keep it for SimulateHotSpotClick().
- if ( inHotSpot != 1 ) return; // sanity check
-
- if ( inCurrInside != inPrevInside ) {
- if ( inCurrInside ) mState = ind_Pressed;
- else mState = ind_Enabled;
- Draw( nil );
- }
- }
-
- void CAGASlider::HotSpotResult(Int16 inHotSpot)
- {
- if (inHotSpot != 1) return;
-
- // done dragging, un-press the indicator
- mState = ind_Enabled;
- Draw( nil );
- }
-
- Boolean CAGASlider::TrackHotSpot(Int16 inHotSpot, Point inPoint)
- {
- #ifndef Debug_Signal
- // inHotSpot is only used in the Assert_(), and therefore only if Debug_Signal is defined.
- #pragma unused(inHotSpot)
- #endif
- Assert_ ( inHotSpot == hot_Indicator || inHotSpot == hot_Track );
-
- #ifdef __PROFILER__
- Boolean profilerIsOn = ProfilerGetStatus();
- ProfilerSetStatus(true); // turn on the profiler
- #endif
-
- mIsTracking = true; // should this be a "St" object?
- mTrackingValue = GetValue();
-
- Rect oldRect, newRect;
- ValueToIndicatorRect(mTrackingValue, newRect);
-
- // "Press" the indicator
- mState = ind_Pressed; // should this be a "St" object?
- mChangedRect = newRect;
- Draw( nil );
-
- // Track the mouse while it is down
- Point currPt = inPoint;
- while (StillDown()) {
-
- ::GetMouse(&currPt);
-
- // calculate ghost position
- Int32 currValue = PositionToValue( currPt );
-
- if ( currValue != mTrackingValue ) {
-
- mTrackingValue = currValue;
-
- if ( mContinuousBroadcast ) {
-
- // this code modified from LControl::BroadcastValueMessage()
- if (mValueMessage != msg_Nothing) {
- Int32 value = mTrackingValue; // broadcast tracking value
- BroadcastMessage(mValueMessage, (void*) &value);
- }
-
- }
-
- // Optimize by remembering the rect that has changed. (new in slider v 1.3.1)
- oldRect = newRect;
- ValueToIndicatorRect(mTrackingValue, newRect);
- ::UnionRect( &oldRect, &newRect, &mChangedRect );
-
- // Note: Draw() must come after BroadcastMessage() since some LListener
- // might do some drawing of it's own and change the drawing focus.
- // We could also just call FocusDraw(), but this saves a few cycles.
- Draw( nil );
- }
- }
-
- mState = ind_Enabled;
- // Check if MouseUp occurred in HotSpot
- EventRecord macEvent; // Get location from MouseUp event
- if (::GetOSEvent(mUpMask, &macEvent)) {
- currPt = macEvent.where;
- ::GlobalToLocal(&currPt);
- mTrackingValue = PositionToValue( currPt );
- }
-
- mIsTracking = false; // must be reset before the final Draw()
-
- SetValue( mTrackingValue ); // SetValue() calls BroadcastValueMessage()
- #ifndef SLIDER_DRAWS_SELF
- Draw( nil );
- #endif // SLIDER_DRAWS_SELF
-
- #ifdef __PROFILER__
- ProfilerSetStatus(profilerIsOn); // turn off the profiler
- #endif
-
- return true; // tell caller that mouse was released in hot-spot
- }
-
- #ifdef SLIDER_DRAWS_SELF
- void CAGASlider::SetValue( Int32 inValue )
- { // If the value changes, pass to superclass and redraw.
-
- if ( inValue != GetValue() ) {
- LControl::SetValue( inValue );
- Draw(nil);
- }
- }
-
- void CAGASlider::EnableSelf()
- {
- Refresh();
- }
-
- void CAGASlider::DisableSelf()
- {
- Refresh();
- }
- #endif // SLIDER_DRAWS_SELF
-